<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Byte and Protocol Converter Tool</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }
        
        .container {
            max-width: 900px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
            overflow: hidden;
        }
        
        .header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }
        
        .header h1 {
            font-size: 28px;
            margin-bottom: 10px;
        }
        
        .header p {
            opacity: 0.9;
            font-size: 14px;
        }
        
        .tabs {
            display: flex;
            background: #f5f5f5;
            border-bottom: 2px solid #ddd;
        }
        
        .tab {
            flex: 1;
            padding: 20px;
            text-align: center;
            cursor: pointer;
            font-weight: bold;
            transition: all 0.3s;
            border: none;
            background: #f5f5f5;
            font-size: 16px;
        }
        
        .tab:hover {
            background: #e0e0e0;
        }
        
        .tab.active {
            background: white;
            color: #667eea;
            border-bottom: 3px solid #667eea;
        }
        
        .content {
            padding: 30px;
        }
        
        .tab-content {
            display: none;
        }
        
        .tab-content.active {
            display: block;
            animation: fadeIn 0.3s;
        }
        
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }
        
        .form-group {
            margin-bottom: 20px;
        }
        
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: bold;
            color: #333;
        }
        
        input[type="text"], textarea {
            width: 100%;
            padding: 12px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 14px;
            font-family: 'Courier New', monospace;
            transition: border-color 0.3s;
        }
        
        input[type="text"]:focus, textarea:focus {
            outline: none;
            border-color: #667eea;
        }
        
        textarea {
            resize: vertical;
            min-height: 100px;
        }
        
        .btn {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            padding: 12px 30px;
            border-radius: 8px;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            transition: transform 0.2s;
        }
        
        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }
        
        .btn:active {
            transform: translateY(0);
        }
        
        .result {
            margin-top: 20px;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 8px;
            border-left: 4px solid #667eea;
        }
        
        .result h3 {
            color: #667eea;
            margin-bottom: 10px;
        }
        
        .result pre {
            background: white;
            padding: 15px;
            border-radius: 5px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            line-height: 1.6;
        }
        
        .error {
            background: #fee;
            border-left-color: #f44;
        }
        
        .error h3 {
            color: #f44;
        }
        
        .example {
            background: #e3f2fd;
            padding: 15px;
            border-radius: 8px;
            margin-top: 20px;
            font-size: 14px;
        }
        
        .example strong {
            color: #1976d2;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>&#x1F527; Byte and Protocol Converter Tool</h1>
            <p>Web Version - No Python Required</p>
        </div>
        
        <div class="tabs">
            <button class="tab active" onclick="switchTab(0)">Byte Conversion</button>
            <button class="tab" onclick="switchTab(1)">Protocol Conversion</button>
        </div>
        
        <div class="content">
            <!-- Byte Conversion (Forward + Reverse) -->
            <div class="tab-content active" id="tab1">
                <!-- Forward Conversion Section -->
                <div style="margin-bottom: 30px; padding: 20px; background: #f0f8ff; border-radius: 10px;">
                    <h3 style="color: #667eea; margin-bottom: 15px;">&#x27A1; Forward Conversion</h3>
                    <p style="margin-bottom: 15px; color: #666; font-size: 14px;">Process: Subtract 0x33 from each byte, then reverse</p>
                    
                    <div class="form-group">
                        <label>Enter hex string:</label>
                        <input type="text" id="byteInput" placeholder="Example: 1B 00 3B or 1B003B" />
                    </div>
                    
                    <button class="btn" onclick="byteConversion()">Convert &#x2192;</button>
                    
                    <div id="byteResult"></div>
                </div>
                
                <!-- Reverse Conversion Section -->
                <div style="margin-bottom: 20px; padding: 20px; background: #fff5f0; border-radius: 10px;">
                    <h3 style="color: #764ba2; margin-bottom: 15px;">&#x2B05; Reverse Conversion</h3>
                    <p style="margin-bottom: 15px; color: #666; font-size: 14px;">Process: Reverse bytes, then add 0x33 to each byte</p>
                    
                    <div class="form-group">
                        <label>Enter hex string:</label>
                        <input type="text" id="reverseInput" placeholder="Example: 08CDE8" />
                    </div>
                    
                    <button class="btn" onclick="reverseConversion()">Convert &#x2190;</button>
                    
                    <div id="reverseResult"></div>
                </div>
                
                <!-- Examples -->
                <div class="example">
                    <strong>Examples:</strong><br><br>
                    <strong>Forward:</strong> <code>1B 00 3B</code> &rarr; <code>08CDE8</code> (Decimal: 577000)<br>
                    <small>1B-33=E8, 00-33=CD, 3B-33=08 &rarr; Reverse &rarr; 08CDE8 &rarr; Decimal: 577000</small><br><br>
                    
                    <strong>Reverse:</strong> <code>08CDE8</code> &rarr; <code>1B003B</code><br>
                    <small>08 CD E8 &rarr; Reverse &rarr; E8 CD 08 &rarr; E8+33=1B, CD+33=00, 08+33=3B</small>
                </div>
            </div>
            
            <!-- Protocol Conversion -->
            <div class="tab-content" id="tab2">
                <div class="form-group">
                    <label>Enter protocol content (hex):</label>
                    <textarea id="protocolInput" placeholder="Example: 68 01 02 03 04 05 06 68 E0 06 4E 33 50 40 3D 38 00 8A 16"></textarea>
                </div>
                
                <button class="btn" onclick="protocolConversion()">Parse Protocol</button>
                
                <div id="protocolResult"></div>
                
                <div class="example">
                    <strong>Supported Protocols:</strong><br>
                    &#x2022; 60 Command (Read Register Request)<br>
                    &#x2022; E0 Command (Read Register Response)<br>
                    &#x2022; 61 Command (Write Register Request)<br>
                    &#x2022; E1 Command (Write Register Response)
                </div>
            </div>
        </div>
    </div>
    
    <script>
        function switchTab(index) {
            const tabs = document.querySelectorAll('.tab');
            const contents = document.querySelectorAll('.tab-content');
            
            tabs.forEach((tab, i) => {
                if (i === index) {
                    tab.classList.add('active');
                    contents[i].classList.add('active');
                } else {
                    tab.classList.remove('active');
                    contents[i].classList.remove('active');
                }
            });
        }
        
        function byteConversion() {
            const input = document.getElementById('byteInput').value.trim();
            const resultDiv = document.getElementById('byteResult');
            
            if (!input) {
                showResult(resultDiv, 'Error: Input cannot be empty', true);
                return;
            }
            
            try {
                const hexBytes = input.replace(/\s+/g, '');
                
                if (hexBytes.length % 2 !== 0) {
                    showResult(resultDiv, 'Error: Hex string length must be even', true);
                    return;
                }
                
                if (!/^[0-9A-Fa-f]+$/.test(hexBytes)) {
                    showResult(resultDiv, 'Error: Input contains invalid hex characters', true);
                    return;
                }
                
                const bytes = [];
                for (let i = 0; i < hexBytes.length; i += 2) {
                    const byteVal = parseInt(hexBytes.substr(i, 2), 16);
                    const newVal = (byteVal - 0x33) & 0xFF;
                    bytes.push(newVal);
                }
                
                bytes.reverse();
                
                const result = bytes.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join('');
                
                let output = `Input: ${input}\n`;
                output += `Process:\n`;
                
                const originalBytes = [];
                for (let i = 0; i < hexBytes.length; i += 2) {
                    originalBytes.push(hexBytes.substr(i, 2).toUpperCase());
                }
                
                const processedBytes = [];
                for (let i = 0; i < originalBytes.length; i++) {
                    const orig = parseInt(originalBytes[i], 16);
                    const processed = (orig - 0x33) & 0xFF;
                    const hex = processed.toString(16).toUpperCase().padStart(2, '0');
                    processedBytes.push(hex);
                    output += `  ${originalBytes[i]} - 33 = ${hex}\n`;
                }
                
                output += `  Result: ${processedBytes.join(' ')}\n`;
                output += `  Reversed: ${processedBytes.reverse().join(' ')}\n`;
                
                // Calculate decimal value
                const decimalValue = parseInt(result, 16);
                output += `  Decimal: ${decimalValue}\n`;
                
                output += `\nOutput: ${result}`;
                
                showResult(resultDiv, output, false);
            } catch (e) {
                showResult(resultDiv, 'Error: ' + e.message, true);
            }
        }
        
        function reverseConversion() {
            const input = document.getElementById('reverseInput').value.trim();
            const resultDiv = document.getElementById('reverseResult');
            
            if (!input) {
                showResult(resultDiv, 'Error: Input cannot be empty', true);
                return;
            }
            
            try {
                const hexBytes = input.replace(/\s+/g, '');
                
                if (hexBytes.length % 2 !== 0) {
                    showResult(resultDiv, 'Error: Hex string length must be even', true);
                    return;
                }
                
                if (!/^[0-9A-Fa-f]+$/.test(hexBytes)) {
                    showResult(resultDiv, 'Error: Input contains invalid hex characters', true);
                    return;
                }
                
                const bytes = [];
                for (let i = 0; i < hexBytes.length; i += 2) {
                    const byteVal = parseInt(hexBytes.substr(i, 2), 16);
                    bytes.push(byteVal);
                }
                
                bytes.reverse();
                
                const resultBytes = [];
                for (let i = 0; i < bytes.length; i++) {
                    const newVal = (bytes[i] + 0x33) & 0xFF;
                    resultBytes.push(newVal);
                }
                
                const result = resultBytes.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join('');
                
                let output = `Input: ${input}\n`;
                output += `Process:\n`;
                
                const originalBytes = [];
                for (let i = 0; i < hexBytes.length; i += 2) {
                    originalBytes.push(hexBytes.substr(i, 2).toUpperCase());
                }
                
                output += `  Original: ${originalBytes.join(' ')}\n`;
                output += `  Reversed: ${originalBytes.reverse().join(' ')}\n`;
                
                const processSteps = [];
                for (let i = 0; i < bytes.length; i++) {
                    const orig = bytes[i];
                    const processed = (orig + 0x33) & 0xFF;
                    const hex = processed.toString(16).toUpperCase().padStart(2, '0');
                    processSteps.push(`${orig.toString(16).toUpperCase().padStart(2, '0')} + 33 = ${hex}`);
                }
                output += `  Add 0x33:\n`;
                processSteps.forEach(step => output += `    ${step}\n`);
                
                output += `\nOutput: ${result}`;
                
                showResult(resultDiv, output, false);
            } catch (e) {
                showResult(resultDiv, 'Error: ' + e.message, true);
            }
        }
        
        function protocolConversion() {
            const input = document.getElementById('protocolInput').value.trim();
            const resultDiv = document.getElementById('protocolResult');
            
            if (!input) {
                showResult(resultDiv, 'Error: Input cannot be empty', true);
                return;
            }
            
            try {
                const hexBytes = input.replace(/\s+/g, '');
                
                if (hexBytes.length % 2 !== 0) {
                    showResult(resultDiv, 'Error: Hex string length must be even', true);
                    return;
                }
                
                if (!/^[0-9A-Fa-f]+$/.test(hexBytes)) {
                    showResult(resultDiv, 'Error: Input contains invalid hex characters', true);
                    return;
                }
                
                const byteArray = [];
                for (let i = 0; i < hexBytes.length; i += 2) {
                    byteArray.push(parseInt(hexBytes.substr(i, 2), 16));
                }
                
                if (byteArray.length < 9) {
                    showResult(resultDiv, 'Error: Protocol data too short', true);
                    return;
                }
                
                if (byteArray[0] !== 0x68) {
                    showResult(resultDiv, 'Error: First byte should be 68', true);
                    return;
                }
                
                if (byteArray[7] !== 0x68) {
                    showResult(resultDiv, 'Error: 8th byte should be 68', true);
                    return;
                }
                
                const a0a5 = byteArray.slice(1, 7);
                const cmdType = byteArray[8];
                
                let output = '='.repeat(50) + '\n';
                output += 'Protocol Parse Result:\n';
                output += '='.repeat(50) + '\n';
                output += `Address A0-A5: ${a0a5.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join(' ')}\n`;
                output += `Command Type: ${cmdType.toString(16).toUpperCase().padStart(2, '0')}\n`;
                
                const dataLen = byteArray[9];
                output += `Data Length: ${dataLen.toString(16).toUpperCase().padStart(2, '0')}\n`;
                
                if (cmdType === 0xE0) {
                    if (dataLen !== 0x06) {
                        showResult(resultDiv, 'Error: E0 command data length should be 06', true);
                        return;
                    }
                    if (byteArray.length < 19) {
                        showResult(resultDiv, 'Error: E0 command data too short', true);
                        return;
                    }
                    
                    const addrBytes = byteArray.slice(10, 12);
                    const addrParsed = parseAddressOrData(addrBytes);
                    output += `Register Addr (raw): ${addrBytes.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join(' ')}\n`;
                    output += `Register Addr (parsed): ${addrParsed}\n`;
                    
                    const dataBytes = byteArray.slice(12, 16);
                    const dataParsed = parseAddressOrData(dataBytes);
                    output += `Register Data (raw): ${dataBytes.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join(' ')}\n`;
                    output += `Register Data (parsed): ${dataParsed}\n`;
                    
                    output += `Fixed Byte: ${byteArray[16].toString(16).toUpperCase().padStart(2, '0')}\n`;
                    if (byteArray.length > 17) output += `Checksum CS: ${byteArray[17].toString(16).toUpperCase().padStart(2, '0')}\n`;
                    if (byteArray.length > 18) output += `End Byte: ${byteArray[18].toString(16).toUpperCase().padStart(2, '0')}\n`;
                    
                } else if (cmdType === 0x60) {
                    if (dataLen !== 0x02) {
                        showResult(resultDiv, 'Error: 60 command data length should be 02', true);
                        return;
                    }
                    if (byteArray.length < 14) {
                        showResult(resultDiv, 'Error: 60 command data too short', true);
                        return;
                    }
                    
                    const addrBytes = byteArray.slice(10, 12);
                    const addrParsed = parseAddressOrData(addrBytes);
                    output += `Register Addr (raw): ${addrBytes.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join(' ')}\n`;
                    output += `Register Addr (parsed): ${addrParsed}\n`;
                    
                    if (byteArray.length > 12) output += `Checksum CS: ${byteArray[12].toString(16).toUpperCase().padStart(2, '0')}\n`;
                    if (byteArray.length > 13) output += `End Byte: ${byteArray[13].toString(16).toUpperCase().padStart(2, '0')}\n`;
                    
                } else if (cmdType === 0x61) {
                    if (dataLen !== 0x06) {
                        showResult(resultDiv, 'Error: 61 command data length should be 06', true);
                        return;
                    }
                    if (byteArray.length < 18) {
                        showResult(resultDiv, 'Error: 61 command data too short', true);
                        return;
                    }
                    
                    const addrBytes = byteArray.slice(10, 12);
                    const addrParsed = parseAddressOrData(addrBytes);
                    output += `Register Addr (raw): ${addrBytes.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join(' ')}\n`;
                    output += `Register Addr (parsed): ${addrParsed}\n`;
                    
                    const dataBytes = byteArray.slice(12, 16);
                    const dataParsed = parseAddressOrData(dataBytes);
                    output += `Register Data (raw): ${dataBytes.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join(' ')}\n`;
                    output += `Register Data (parsed): ${dataParsed}\n`;
                    
                    if (byteArray.length > 16) output += `Checksum CS: ${byteArray[16].toString(16).toUpperCase().padStart(2, '0')}\n`;
                    if (byteArray.length > 17) output += `End Byte: ${byteArray[17].toString(16).toUpperCase().padStart(2, '0')}\n`;
                    
                } else if (cmdType === 0xE1) {
                    if (dataLen !== 0x00) {
                        showResult(resultDiv, 'Error: E1 command data length should be 00', true);
                        return;
                    }
                    if (byteArray.length < 12) {
                        showResult(resultDiv, 'Error: E1 command data too short', true);
                        return;
                    }
                    
                    if (byteArray.length > 10) output += `Checksum CS: ${byteArray[10].toString(16).toUpperCase().padStart(2, '0')}\n`;
                    if (byteArray.length > 11) output += `End Byte: ${byteArray[11].toString(16).toUpperCase().padStart(2, '0')}\n`;
                    
                } else {
                    output += `Warning: Unknown command type ${cmdType.toString(16).toUpperCase().padStart(2, '0')}\n`;
                }
                
                output += '='.repeat(50);
                
                showResult(resultDiv, output, false);
            } catch (e) {
                showResult(resultDiv, 'Error: ' + e.message, true);
            }
        }
        
        function parseAddressOrData(bytes) {
            const processed = bytes.map(b => (b - 0x33) & 0xFF);
            processed.reverse();
            return processed.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join('');
        }
        
        function showResult(div, text, isError) {
            div.innerHTML = `
                <div class="result ${isError ? 'error' : ''}">
                    <h3>${isError ? '&#x274C; Error' : '&#x2705; Result'}</h3>
                    <pre>${text}</pre>
                </div>
            `;
        }
    </script>
</body>
</html>


